# AlreadyAssignedIdentifierManager.java

    package org.codefilarete.stalactite.mapping.id.manager;

    import java.util.Set;
    import java.util.function.Consumer;
    import java.util.function.Function;

    import org.codefilarete.stalactite.engine.listener.InsertListener;
    import org.codefilarete.stalactite.engine.listener.SelectListener;
    import org.codefilarete.stalactite.engine.runtime.WriteExecutor.JDBCBatchingIterator;
    import org.codefilarete.stalactite.mapping.SimpleIdMapping;
    import org.codefilarete.stalactite.sql.ddl.structure.Column;
    import org.codefilarete.stalactite.sql.ddl.structure.Table;
    import org.codefilarete.stalactite.sql.statement.WriteOperation;

    /**
     * Identifier manager to be used when identifier is already specified on entity, therefore this requires :
     * <ul>
     * <li>a way to know if entity is already present in database, this is left to a {@link Function}&lt;C, Boolean&gt;</li>
     * <li>the entity to be marked as persisted in any kind of way, this is left to a {@link Consumer}</li>
     * </ul>
     *
     * A way o managing it can be to create a wrapper around identifier.
     *
     * @author Guillaume Mary
     * @see SimpleIdMapping.IsNewDeterminer#isNew(Object)
     */
    public class AlreadyAssignedIdentifierManager<C, I> implements IdentifierInsertionManager<C, I> {

    	private final Class<I> identifierType;

    	private final SetPersistedFlagAfterInsertListener setPersistedFlagAfterInsertListener = new SetPersistedFlagAfterInsertListener();

    	private final SetPersistedFlagAfterSelectListener setPersistedFlagAfterSelectListener = new SetPersistedFlagAfterSelectListener();

    	/** The {@link Consumer} that allows instances to be marked as persisted */
    	private final Consumer<C> markAsPersistedFunction;

    	/** The {@link Function} that allows to know if an instance is already persisted (expected to exist in database) */
    	private final Function<C, Boolean> isPersistedFunction;

    	public AlreadyAssignedIdentifierManager(Class<I> identifierType,
    											Consumer<C> markAsPersistedFunction,
    											Function<C, Boolean> isPersistedFunction) {
    		this.identifierType = identifierType;
    		this.markAsPersistedFunction = markAsPersistedFunction;
    		this.isPersistedFunction = isPersistedFunction;
    	}

    	@Override
    	public Class<I> getIdentifierType() {
    		return identifierType;
    	}

    	public Consumer<C> getMarkAsPersistedFunction() {
    		return markAsPersistedFunction;
    	}

    	public Function<C, Boolean> getIsPersistedFunction() {
    		return isPersistedFunction;
    	}

    	@Override
    	public JDBCBatchingIterator<C> buildJDBCBatchingIterator(Iterable<? extends C> entities, WriteOperation<? extends Column<? extends Table, ?>> writeOperation, int batchSize) {
    		return new JDBCBatchingIterator<>(entities, writeOperation, batchSize);
    	}

    	public InsertListener<C> getInsertListener() {
    		return this.setPersistedFlagAfterInsertListener;
    	}

    	public SelectListener<C, I> getSelectListener() {
    		return this.setPersistedFlagAfterSelectListener;
    	}

    	public void setPersistedFlag(C e) {
    		if (markAsPersistedFunction != null ) {
    			markAsPersistedFunction.accept(e);
    		}
    	}

    	private class SetPersistedFlagAfterInsertListener implements InsertListener<C> {

    		@Override
    		public void afterInsert(Iterable<? extends C> entities) {
    			markAsPersisted(entities);
    		}
    	}

    	private class SetPersistedFlagAfterSelectListener implements SelectListener<C, I> {

    		@Override
    		public void afterSelect(Set<? extends C> entities) {
    			markAsPersisted(entities);
    		}
    	}

    	/**
    	 * Massive version of {@link #setPersistedFlag(Object)}, made to avoid code duplicate between {@link SetPersistedFlagAfterInsertListener}
    	 * and {@link SetPersistedFlagAfterSelectListener}
    	 *
    	 * @param entities entities to be marked as persisted
    	 */
    	protected void markAsPersisted(Iterable<? extends C> entities) {
    		for (C e : entities) {
    			setPersistedFlag(e);
    		}
    	}
    }